package it.unibo.refolding.pico;

import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.doubles.DoubleList;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.common.base.Preconditions;

public class PeakOrNot {
	public static final PeakOrNot NON_PEAK = new PeakOrNot(-1, 0);
	
	final int startSlopeIndex;
	final double nonNegativeContourLengthMetres;

	public static PeakOrNot of(int startSlopeIndex, double contourLength) {
		if (startSlopeIndex == -1 && contourLength == 0) {
			return NON_PEAK;
		} else {
			return new PeakOrNot(startSlopeIndex, contourLength);
		}
	}
	
	private PeakOrNot(int startSlopeIndex, double contourLength) {
		Preconditions.checkArgument(startSlopeIndex >= -1, startSlopeIndex);
		Preconditions.checkArgument(contourLength >= 0, contourLength);
		Preconditions.checkArgument(startSlopeIndex != -1 | contourLength == 0,
				"A non-peak cannot have contour length.");
		this.startSlopeIndex = startSlopeIndex;
		this.nonNegativeContourLengthMetres = contourLength;
	}

	public boolean isPeak() {
		return startSlopeIndex != -1;
	}

	@Override
	public String toString() {
		return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
	}

	public boolean hasContorLength() {
		return nonNegativeContourLengthMetres != 0;
	}

	public static int countPeaks(PeakOrNot[] peakOrNots) {
		int count = 0;
		for (PeakOrNot peakOrNot : peakOrNots) {
			if (peakOrNot.isPeak()) {
				count++;
			}
		}
		return count;
	}

	public static DoubleList contourLengths(PeakOrNot[] peakOrNots) {
		DoubleList list = new DoubleArrayList();
		for (int i = 0; i < peakOrNots.length; ++i) {
			if (peakOrNots[i].isPeak()) {
				list.add(peakOrNots[i].nonNegativeContourLengthMetres);
			}
		}
		return list;
	}

	/**
	 * @return -1 if there are no peaks
	 */
	public static int lastPeakindex(PeakOrNot[] peakOrNots) {
		int i;
		for (i = peakOrNots.length; --i >= 0; ) {
			if (peakOrNots[i].isPeak()) {
				break;
			}
		}
		return i;
	}
}
